#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/wait.h>


 
struct device_test
{
   dev_t  dev_num;  //定义dev_t类型变量来表示设备号
   int major,minor; //定义int 类型的主设备号和次设备号
   struct cdev cdev_test;   //定义字符设备
   struct class *class;   //定义结构体变量class 类
   struct device *device;  // 设备
   char kbuf[32];
   int flag;               //标志位

};
struct device_test dev1;  
 
 DECLARE_WAIT_QUEUE_HEAD(read_wq);

/*打开设备函数*/
static int open_test(struct  inode  *inode,struct file *file)
 {
    
    file->private_data=&dev1;//设置私有数据
    printk("\n this is open_test \n");
    return 0;
 };
 

static ssize_t read_test(struct file *file,char __user *buf,size_t len,loff_t *off)
{
    struct device_test *test_dev=(struct device_test *)file->private_data;
	wait_event_interruptible(read_wq,test_dev->flag); //可中断的阻塞等待，使进程进入休眠态
	printk("\nthis is read_test \n");
    if (copy_to_user(buf, test_dev->kbuf, strlen( test_dev->kbuf)) != 0){ // copy_to_user:内核空间向用户空间传数据
		printk("copy_to_user is error \n");
	}
	printk("copy_to_user is ok \n");
	return 0;
}
/*向设备写入数据函数*/
static ssize_t cdev_test_write(struct file *file, const char __user *buf, size_t size, loff_t *off)
{
     struct device_test *test_dev=(struct device_test *)file->private_data;

    if (copy_from_user(test_dev->kbuf, buf, size) != 0) // copy_from_user:用户空间向内核空间传数据
    {
        printk("copy_from_user error\r\n");
        return -1;
    }
    test_dev->flag=1;//将条件置1
    wake_up_interruptible(&read_wq); //并使用wake_up_interruptible唤醒等待队列中的休眠进程

    return 0;
}


static int release_test(struct inode *inode,struct file *file)
{
   printk("\nthis is release_test \n");
   return 0;
}






static struct file_operations fops_test = {
	.owner=THIS_MODULE,//将owner字段指向本模块，可以避免在模块的操作正在被使用时卸载该模块
    .open = open_test,//将open字段指向chrdev_open(...)函数
    .read = read_test,//将open字段指向chrdev_read(...)函数
    .write = cdev_test_write,//将open字段指向chrdev_write(...)函数
    .release = release_test,//将open字段指向chrdev_release(...)函数
};//定义file_operations结构体类型的变量cdev_test_ops




static int __init chrdev_fops_init(void)//驱动入口函数
{

    if(alloc_chrdev_region(&dev1.dev_num,0,1,"chrdev_name") < 0){
            printk("alloc_chrdev_region is error\n");
    }   
        printk("alloc_chrdev_region is ok\n");
        dev1.major=MAJOR(dev1.dev_num);//通过MAJOR()函数进行主设备号获取
        dev1.minor=MINOR(dev1.dev_num);//通过MINOR()函数进行次设备号获取
        printk("major is %d\n",dev1.major);
        printk("minor is %d\n",dev1.minor);
 
        ////使用cdev_init()函数初始化cdev_test结构体，并链接到cdev_test_ops结构体
        cdev_init(&dev1.cdev_test,&fops_test);
        dev1.cdev_test.owner = THIS_MODULE;//将owner字段指向本模块，可以避免在模块的操作正在被使用时卸载该模块 

        cdev_add(&dev1.cdev_test,dev1.dev_num,1);
        printk("cdev_add is ok\n");
        dev1.class  = class_create(THIS_MODULE,"test");//使用class_create进行类的创建，类名称为class_test
        device_create(dev1.class,NULL,dev1.dev_num,NULL,"test");//使用device_create进行设备的创建，设备名称为device_test

    return 0;
}
static void __exit chrdev_fops_exit(void)//驱动出口函数
{
    cdev_del(&dev1.cdev_test);//使用cdev_del()函数进行字符设备的删除
    unregister_chrdev_region(dev1.dev_num,1);//释放字符驱动设备号 
    device_destroy(dev1.class,dev1.dev_num);//删除创建的设备
    class_destroy(dev1.class);//删除创建的类
    printk("module exit \n");

}
module_init(chrdev_fops_init);//注册入口函数
module_exit(chrdev_fops_exit);//注册出口函数
MODULE_LICENSE("GPL v2");//同意GPL开源协议
MODULE_AUTHOR("wang fang chen "); //作者信息
